/*
 * $Id:
 *
 * Copyright (C) 2011 Refiner Inc.
 * All right reserved
 *
 *============================================================
 * +rVPN Stack : AppIF (Socket Base Interface)
 *============================================================
 * abstract: This module provides TCP/IP stack interface
 * author  : MURATA
 * history :
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <rts_socket.h>
#include "rvs_appif.h"
#include "rsi_apisock.h"
#include "rsi_tcpipif.h"
#include "bsd_socket.h"
#include "../rvpncif/rvm_vif.h"
#include "../rvpncif/rvpncif.h"
#include "rvs_helpif.h"

#ifndef MAXTIMECHECK
#define MAXTIMECHECK	0
#endif

static int optconv[][2] = {
    { SO_DEBUG, BSD_SO_DEBUG },
    { SO_ACCEPTCONN, BSD_SO_ACCEPTCONN },
    { SO_REUSEADDR, BSD_SO_REUSEADDR },
    { SO_KEEPALIVE, BSD_SO_KEEPALIVE },
    { SO_DONTROUTE, BSD_SO_DONTROUTE },
    { SO_BROADCAST, BSD_SO_BROADCAST },
    { SO_LINGER, BSD_SO_LINGER },
    { SO_OOBINLINE, BSD_SO_OOBINLINE },
    { SO_SNDBUF, BSD_SO_SNDBUF },
    { SO_RCVBUF, BSD_SO_RCVBUF },
    { SO_SNDLOWAT, BSD_SO_SNDLOWAT },
    { SO_RCVLOWAT, BSD_SO_RCVLOWAT },
    { SO_SNDTIMEO, BSD_SO_SNDTIMEO },
    { SO_RCVTIMEO, BSD_SO_RCVTIMEO },
    { SO_ERROR, BSD_SO_ERROR },
    { SO_TYPE, BSD_SO_TYPE },
    { 0 }
};

static int sol_conv(int level)
{
    if (level == SOL_SOCKET) {
        return BSD_SOL_SOCKET;
    }
    return 0;
}

static int opt_conv(int opt)
{
    int i;

    for(i=0; optconv[i][0] ; i++) {
        if (opt == optconv[i][0])
            return optconv[i][1];
    }

    return 0;
}

#if MAXTIMECHECK
/* 性能計測用 */
//#define MAXTIMECHECK    1024
static struct timeval chktv[MAXTIMECHECK];
static unsigned short chkln[MAXTIMECHECK];
static unsigned int chkpkt[MAXTIMECHECK];
static int ntm=0;
#define IPUDPHDR_LEN    28

static void _trace_time(const char* msg,char* buf,int len)
{
    if (buf==NULL) buf = "0000";

    /* 性能計測用 */
    if (ntm == MAXTIMECHECK) {
        int i;
        for (i=0; i<MAXTIMECHECK; i++) {
            fprintf(stderr, "%s[%04d]: %u.%06u %u %08X\n", msg,
               i,(unsigned int)chktv[i].tv_sec,(unsigned int)chktv[i].tv_usec,
                chkln[i], chkpkt[i]);
        }
        ntm=0;
    } else if (ntm < MAXTIMECHECK) {
        gettimeofday(&chktv[ntm], NULL);
        chkln[ntm] = len;
        chkpkt[ntm] = *(unsigned int*)buf;
        ntm++;
    }
}
#else
#define _trace_time(a,b,c)       {}
#endif

static rsi_tifct_t _rsi_cont[RSI_MAX_CONTS];

/* リクエスト処理関数群 */
static int rsi_tif_socket(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_close(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_bind(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_connect(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_listen(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_accept(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_sendto(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_recvfrom(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_send(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_recv(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_setsockopt(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_getsockopt(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_getaddrinfo(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_getsockname(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_ioctl(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_fcntl(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_shutdown(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_select(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_getlocalif(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_getvifroute(rsi_tifct_t* ct, rvs_api_msg_t* msg);
static int rsi_tif_statuscheck(rsi_tifct_t* ct, rvs_api_msg_t* msg);

typedef struct _request_tab {
    int msgcode;
    int (*reqfunc)(rsi_tifct_t*, rvs_api_msg_t*);
} request_tab_t;

static request_tab_t rsi_reqs[] = {
    { RAPI_M_SOCKET, rsi_tif_socket },
    { RAPI_M_CLOSE, rsi_tif_close },
    { RAPI_M_BIND, rsi_tif_bind },
    { RAPI_M_CONNECT, rsi_tif_connect },
    { RAPI_M_LISTEN, rsi_tif_listen },
    { RAPI_M_ACCEPT, rsi_tif_accept },
    { RAPI_M_SENDTO, rsi_tif_sendto },
    { RAPI_M_RECVFROM, rsi_tif_recvfrom },
    { RAPI_M_SEND, rsi_tif_send },
    { RAPI_M_RECV, rsi_tif_recv },
    { RAPI_M_SETSOCKOPT, rsi_tif_setsockopt },
    { RAPI_M_GETSOCKOPT, rsi_tif_getsockopt },
    { RAPI_M_GETADDRINFO, rsi_tif_getaddrinfo },
    { RAPI_M_GETSOCKNAME, rsi_tif_getsockname },
    { RAPI_M_IOCTL, rsi_tif_ioctl },
    { RAPI_M_FCNTL, rsi_tif_fcntl },
    { RAPI_M_SHUTDOWN, rsi_tif_shutdown },
    { RAPI_M_SELECT, rsi_tif_select },
    { RAPI_M_GETLOCALIF, rsi_tif_getlocalif },
    { RAPI_M_GETVIFROUTE, rsi_tif_getvifroute },
    { RAPI_M_STATUSCHECK, rsi_tif_statuscheck },
    { 0 }
};

/* TIFコンテキスト領域の確保 */
rsi_tifct_t* rsi_tif_new(int msgcode, rsi_sock_t* rsock)
{
    int i;
    rsi_tifct_t* ct = _rsi_cont;
    for (i=0; i<RSI_MAX_CONTS; i++, ct++) {
        if (!ct->used) {
            ct->used = 1;
            ct->msgcode = (uint16_t)msgcode;
            ct->rsock = rsock;
            return ct;
        }
    }
    LOGE("%s: No CT remained\n", __FUNCTION__);
    return NULL;
}

/* TIFコンテキスト領域の開放 */
void rsi_tif_free(rsi_tifct_t* ct)
{
    /* msgcodeにより解放する領域があれば解放する */
    /* switch (ct->msgcode) { */
    if (ct->args) {
        rvs_free(ct->args);
    }
    
//2011.09.12 koyama Mantis#900 修正
//    memset (ct, 0, sizeof(rsi_tifct_t));
    memset (((void *)ct)+sizeof(ct->used), 0, sizeof(rsi_tifct_t)-sizeof(ct->used));
    ct->used = 0;    // usedを最後にクリア
}

void* rsi_tif_allocargs(rsi_tifct_t* ct, int size)
{
    ct->args = rvs_malloc(size);
    if (ct->args != NULL) {
        memset (ct->args, 0, size);
    } else {
        rsi_tif_senderr(ct, ENOMEM);
    }
    return ct->args;
}

/* 初期化 */
void rsi_tif_init(void)
{
    rts_callbacks_t cbs;

    /* TCP/IPスタックの初期化 */
    rts_init(NULL,NULL,5);

    /* コールバック関数の登録 */
    cbs.cb_socket = &rsi_cb_socket;
    cbs.cb_close = &rsi_cb_close;
    cbs.cb_bind = &rsi_cb_bind;
    cbs.cb_listen = &rsi_cb_listen;
    cbs.cb_connect = &rsi_cb_connect;
    cbs.cb_accept = &rsi_cb_accept;
    cbs.cb_send = &rsi_cb_send;
    cbs.cb_recv = &rsi_cb_recv;
    cbs.cb_sendto = &rsi_cb_sendto;
    cbs.cb_recvfrom = &rsi_cb_recvfrom;
    cbs.cb_select = &rsi_cb_select;
    cbs.cb_ioctl = &rsi_cb_ioctl;
    cbs.cb_getpeername = &rsi_cb_getpeername;
    cbs.cb_getsockname = &rsi_cb_getsockname;
    cbs.cb_getsockopt = &rsi_cb_getsockopt;
    cbs.cb_setsockopt = &rsi_cb_setsockopt;
    cbs.cb_shutdown = &rsi_cb_shutdown;

    rts_set_callbacks(&cbs);

    /* TCPIP I/F 管理領域の初期化  */
    memset (_rsi_cont, 0, sizeof(_rsi_cont));
}

void rsi_tif_stop(void)
{
}

/* リクエスト受付処理 */
int rsi_tif_request(rsi_sock_t* rsock)
{
    int ret = 0;
    request_tab_t* req;

    rvs_api_msg_t* msg = rsi_apisock_rmsg(rsock);
    /* 2011.9.16 すでに解放されているか？ */
    if (msg == NULL) {
        LOGE("%s: cannot get apisock\n", __FUNCTION__);
        return -1;
    }
    /* TIF管理領域の確保 */
    rsi_tifct_t* ct = rsi_tif_new(msg->header->msgcode, rsock);

    if (ct == NULL) {
        rsi_tifct_t tmpct = { 1, msg->header->msgcode, msg->header->seqno,
                              0, rsock, NULL};
        rsi_apisock_release(rsock);
        rsi_tif_senderr(&tmpct,  ENOBUFS);
		ret = -1;  /* 2011.9.16 */
        goto reqexit;
    }
    rsi_apisock_release(rsock);

    ct->seqno = msg->header->seqno;

    for (req = rsi_reqs; req->msgcode; req++) {
        if (req->msgcode == ct->msgcode) {
            if ((*req->reqfunc)(ct, msg) < 0) {
                rsi_tif_free(ct);
            }
            break;
        }
    }

reqexit:
    return ret;
}

static int rsi_tif_socket(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    /* 引数チェック */
    if (!msg->domain || !msg->type || !msg->proto) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* TCPIPスタックを呼び出す */
    rts_socket (msg->domain->Integer, msg->type->Integer, msg->proto->Integer, ct);
    return 0;
}

static int rsi_tif_close(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    /* 引数チェック */
    if (!msg->rsock) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* TCPIPスタックを呼び出す */
    rts_close(msg->rsock->Integer, ct);
    return 0;
}

static int rsi_tif_bind(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    rvsaddr_t addr;
    socklen_t addrlen;

    /* 引数チェック */
    if (!msg->rsock || (!msg->addrv4 && !msg->addrv6)) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* リクエストメッセージからアドレスを取り出す */
    addrlen = rvs_get_addr(msg, &addr.sa, sizeof(addr));

    /* TCPIPスタックを呼び出す */
    rts_bind(msg->rsock->Integer, &addr.sa, addrlen, ct);
    return 0;
}

static int rsi_tif_connect(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    rvsaddr_t addr;
    socklen_t addrlen;

    /* 引数チェック */
    if (!msg->rsock || (!msg->addrv4 && !msg->addrv6)) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* リクエストメッセージからアドレスを取り出す */
    addrlen = rvs_get_addr(msg, &addr.sa, sizeof(addr));

    /* TCPIPスタックを呼び出す */
    rts_connect(msg->rsock->Integer, &addr.sa, addrlen, ct);
    return 0;
}

static int rsi_tif_listen(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    /* 引数チェック */
    if (!msg->rsock || !msg->backlog) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* TCPIPスタックを呼び出す */
    rts_listen(msg->rsock->Integer, msg->backlog->Integer, ct);
    return 0;
}

static int rsi_tif_accept(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    accept_args_t* args;

    /* 引数チェック */
    if (!msg->rsock) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* 出力引数領域の確保 */
    args = rsi_tif_allocargs(ct, sizeof(accept_args_t));
    if (args == NULL) {
        return -1;
    }
    args->addrlen = sizeof(args->addr);
    
    /* TCPIPスタックを呼び出す */
    rts_accept(msg->rsock->Integer, 
           &args->addr.sa, &args->addrlen, ct);
    return 0;
}

static int rsi_tif_sendto(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    int flags=0;
    rvsaddr_t addr;
    socklen_t addrlen;

    /* 引数チェック */
    if (!msg->rsock || !msg->data || (!msg->addrv4 && !msg->addrv6)) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }
    if (msg->flags) {
        flags = msg->flags->Integer;
    }

    /* リクエストメッセージからアドレスを取り出す */
    addrlen = rvs_get_addr(msg, &addr.sa, sizeof(addr));

    _trace_time(__FUNCTION__, (char*)msg->data->Buffer, msg->data->Length);

    /* TCPIPスタックを呼び出す */
    rts_sendto(msg->rsock->Integer, msg->data->Buffer, msg->data->Length,
               flags, &addr.sa, addrlen, ct);
    return 0;
}

static int rsi_tif_recvfrom(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    recvfrom_args_t* args;
    int length = 0x10000;
    int flags = 0;

    /* 引数チェック */
    if (!msg->rsock ) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }
    if (msg->flags) {
        flags = msg->flags->Integer;
    }

    /* 受信バッファサイズによりパラメータ領域のサイズ決定 */
    if (msg->header->status > 0) {
        length = msg->header->status;
    }
    args = rsi_tif_allocargs(ct, sizeof(recvfrom_args_t)+length);
    if (args == NULL) {
        return -1;
    }
    args->addrlen = sizeof(args->addr);

    /* TCPIPスタックを呼び出す */
    rts_recvfrom(msg->rsock->Integer, args->buffer, length,
               flags, &args->addr.sa, &args->addrlen, ct);
    return 0;

}

static int rsi_tif_send(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    int flags=0;

    /* 引数チェック */
    if (!msg->rsock || !msg->data ) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }
    if (msg->flags) {
        flags = msg->flags->Integer;
    }

    _trace_time(__FUNCTION__, (char*)msg->data->Buffer, msg->data->Length);

    /* TCPIPスタックを呼び出す */
    rts_send(msg->rsock->Integer, msg->data->Buffer, msg->data->Length,
               flags, ct);
    return 0;
}

static int rsi_tif_recv(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    recv_args_t* args;
    int length = 0x10000;
    int flags = 0;

    LOGD("%s: Enter\n", __FUNCTION__);

    /* 引数チェック */
    if (!msg->rsock ) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }
    if (msg->flags) {
        flags = msg->flags->Integer;
    }

    /* 受信バッファサイズによりパラメータ領域のサイズ決定 */
    if (msg->header->status > 0) {
        length = msg->header->status;
    }
    args = rsi_tif_allocargs(ct, length);
    if (args == NULL) {
        return -1;
    }

    /* TCPIPスタックを呼び出す */
    LOGD("%s: call rts_recv(fd=%d,length=%d,flags=0x%x\n", __FUNCTION__,
           msg->rsock->Integer, length, flags);
    rts_recv(msg->rsock->Integer, args->buffer, length, flags, ct);
    return 0;

}

static int rsi_tif_setsockopt(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    /* 引数チェック */
    if (!msg->rsock || !msg->level || !msg->option || !msg->value) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* Level,Optionの変換 */
    msg->level->Integer = sol_conv(msg->level->Integer);
    msg->option->Integer = opt_conv(msg->option->Integer);

    /* TCPIPスタックを呼び出す */
    rts_setsockopt(msg->rsock->Integer, msg->level->Integer, msg->option->Integer,
               msg->value->String, msg->value->Length, ct);
    return 0;
}

static int rsi_tif_getsockopt(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    getsockopt_args_t* args;

    /* 引数チェック */
    if (!msg->rsock || !msg->level || !msg->option ||
                                     (msg->header->status <= 0)) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* 出力引数 */
    args = rsi_tif_allocargs(ct,sizeof(getsockopt_args_t)+msg->header->status);
    if (args == NULL) {
        return -1;
    }
    args->length = msg->header->status;

    /* Level,Optionの変換 */
    msg->level->Integer = sol_conv(msg->level->Integer);
    msg->option->Integer = opt_conv(msg->option->Integer);

    /* TCPIPスタックを呼び出す */
    rts_getsockopt(msg->rsock->Integer, msg->level->Integer, msg->option->Integer,
               args->buffer, (socklen_t *)&args->length, ct);
    return 0;
}

static int rsi_tif_getaddrinfo(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    rsi_tif_senderr(ct, EPERM);
    return -1;
}

static int rsi_tif_getsockname(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    getsockname_args_t* args;

    /* 引数チェック */
    if (!msg->rsock) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* 出力引数領域の確保 */
    args = rsi_tif_allocargs(ct, sizeof(getsockname_args_t));
    if (args == NULL) {
        return -1;
    }
    memset (&args->addr, 0, sizeof(args->addr));
    args->addrlen = sizeof(args->addr);

    /* TCPIPスタックを呼び出す */
    rts_getsockname(msg->rsock->Integer,
           &args->addr.sa, &args->addrlen, ct);
    return 0;
}

static int rsi_tif_ioctl(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    ioctl_args_t* args;
    int arglen = 0;

    /* 引数チェック */
    if (!msg->rsock || !msg->option) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    switch (msg->option->Integer) {
    case FIONBIO:
        arglen = sizeof(int);
        break;
    default:
        rsi_tif_senderr(ct, EPERM);
        return -1;
    }

    /* 引数領域確保 */
    if (msg->value) {
        arglen = msg->value->Length;
    }
    args = rsi_tif_allocargs(ct, sizeof(ioctl_args_t)+arglen);
    if (args == NULL) {
        return -1;
    }
    args->length = arglen;
    if (msg->value) {
        memcpy (args->buffer, msg->value->String, arglen);
    }

    /* TCPIPスタックを呼び出す */
    rts_ioctl(msg->rsock->Integer, msg->option->Integer,
               args->buffer, ct);
    return 0;
}

static int rsi_tif_fcntl(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    ioctl_args_t* args;
    int request;
    long val;
    int arglen = 0;

    /* 引数チェック */
    if (!msg->rsock || !msg->option) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    switch (msg->option->Integer) {
    case F_SETFL:
        arglen = sizeof(long);
        if (msg->value) {
            if ((*(int*)msg->value->String) & ~O_NONBLOCK) {
                goto errperm;
            }
            request = FIONBIO;
            if ((*(int*)msg->value->String) & O_NONBLOCK) {
                val = 1;
            } else {
                val = 0;
            }
        } else {
            goto errperm;
        }
        break;
    default:
        goto errperm;
    }

    /* 引数領域確保 */
    args = rsi_tif_allocargs(ct, sizeof(ioctl_args_t)+arglen);
    if (args == NULL) {
        return -1;
    }
    args->length = arglen;
    *(long*)args->buffer = val;

    /* TCPIPスタックを呼び出す */
    rts_ioctl(msg->rsock->Integer, request, args->buffer, ct);
    return 0;

errperm:
    rsi_tif_senderr(ct, EPERM);
    return -1;
}

static int rsi_tif_shutdown(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    /* 引数チェック */
    if (!msg->rsock || !msg->how) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* TCPIPスタックを呼び出す */
    rts_shutdown(msg->rsock->Integer, msg->how->Integer, ct);
    return 0;
}

static int rsi_tif_select(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    select_args_t* args;
    struct timeval *tvp=NULL;

    /* 引数チェック */
    if (!msg->selist) {
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    /* 引数領域の確保 */
    args = rsi_tif_allocargs(ct, sizeof(select_args_t));
    if (args == NULL) {
        return -1;
    }

    /* 引数の読み込み */
    args->nfds = rvs_get_fdsets(msg, &args->readfds, &args->writefds,
                                &args->exceptfds);

    if (msg->timeout) {
        args->tv.tv_sec = msg->timeout->Integer / 1000;
        args->tv.tv_usec = msg->timeout->Integer % 1000 * 1000;
        tvp = &args->tv;
    }

    //LOGD("%s: call rts_select(nfds=%d,rf=%p,wf=%p,ef=%p,ct=%p)\n",
    //     __FUNCTION__, args->nfds, &args->readfds, &args->writefds, &args->exceptfds, ct);

    /* TCPIPスタックを呼び出す */
    rts_select(args->nfds, &args->readfds, &args->writefds,
                     &args->exceptfds, tvp, ct);
    return 0;
}

/* ローカルI/F取得関数 */
static void rsi_getlocalif(int type, struct sockaddr* addr, socklen_t* addrlen, void* context)
{
    int result = rvm_vif_getaddr(type, addr, addrlen);

    if (result < 0) {
        LOGE("%s: Invalid Args(type=%d,addrlen=%d).\n", __FUNCTION__, type, *addrlen);
        result = -EINVAL;
    }

    LOGD("%s: KIND:%d - %s\n", __FUNCTION__, type,
        (addr->sa_family==AF_INET)?inet_ntoa(((struct sockaddr_in*)addr)->sin_addr):"INET6");
    rsi_cb_getlocalif(addr, addrlen, result, context);
}

static int rsi_tif_getlocalif(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    accept_args_t* args;

    if (msg->type == NULL) {
        LOGE("%s: Invalid Args(Kind=NULL)\n",__FUNCTION__);
        rsi_tif_senderr(ct, EINVAL);
        return -1;
    }

    LOGD("%s: Enter(kind=%d)\n", __FUNCTION__, msg->type->Integer);

    /* 出力引数領域の確保 */
    args = rsi_tif_allocargs(ct, sizeof(accept_args_t));
    if (args == NULL) {
        LOGD("%s: cannot allocate args\n", __FUNCTION__);
        return -1;
    }
    args->addrlen = sizeof(args->addr);

    /* 代替関数を呼び出す */
    rsi_getlocalif(msg->type->Integer,
           &args->addr.sa, &args->addrlen, ct);
    return 0;
}

static int rsi_tif_getvifroute(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    struct sockaddr addr, daddr;
    socklen_t addrlen, daddrlen;
    int vifno;
    int sts=0;

    LOGD("%s: Enter\n", __FUNCTION__);

    /* 引数チェック */
    if (!(msg->addrv4 || msg->daddrv4)) {
      LOGD("%s: no addr info\n", __FUNCTION__);
      rsi_tif_senderr(ct, EINVAL);
      return -1;
    }

    /* リクエストメッセージからアドレスを取り出す */
    addrlen  = rvs_get_addr(msg, &addr, sizeof(addr));    /* source address */
    daddrlen = rvs_get_daddr(msg, &daddr, sizeof(daddr));  /* destination address */

    if(daddrlen < 0){ /* if only source address is specified. */
      vifno = rvm_get_vif_addr(&addr);
    }
    else{
    /* 仮想インタフェーフェース問合せ（ルーティング） */
    /* if no route found, rvm_get_vif_route() return -1  */
      vifno= rvm_get_vif_route(addrlen < 0 ? NULL: &addr, &daddr, NULL);
    }

    rsi_cb_getvifroute(vifno, sts, ct);

    return 0;
}

static void rsi_statuscheck(rvs_status_t* statusp, rvs_error_t* errorp, void* context)
{
    int result = rvm_status_check(statusp, errorp);

    if (result < 0) {
        LOGE("%s: rvm_status_check() error.\n", __FUNCTION__);
    }

    rsi_cb_statuscheck(statusp, errorp, result, context);
}

static int rsi_tif_statuscheck(rsi_tifct_t* ct, rvs_api_msg_t* msg)
{
    status_args_t* args;

    LOGD("%s: Enter\n", __FUNCTION__);

    /* 出力引数領域の確保 */
    args = rsi_tif_allocargs(ct, sizeof(status_args_t));
    if (args == NULL) {
        LOGD("%s: cannot allocate args\n", __FUNCTION__);
        return -1;
    }

    /* 相手ユーザ名リスト */
    args->status.p2pcon = MAX_P2PCON;
    args->status.remotename = args->remotes;

    /* 代替関数を呼び出す */
    rsi_statuscheck(&args->status, &args->error, ct);
    return 0;

}

